/********************************************************************************
 * Copyright (c)2016-2020, ShenZhen WanJiaAn Technology CO.,LTD.
 * All Rights Reserved.
 *
 * File Name     : app_main.c
 * Author        : joki.zhu
 * Date          : 2019-09-19
 *
 * Record        :
 * 1.Date        : 2019-09-19
 *   Author      : joki.zhu
 *   Modification: Created file
 ********************************************************************************/

#include "app_common.h"
#include "product_shell.h"
#include "protocol.h"
#include "config_management.h"
#include "ProductManager.h"
#include "DevManager.h"
#include "PowerManager.h"
#include "partition_table.h"
#include "DevConfig.h"
#include "LogManager.h"
#include "hi_hal_syslink.h"
#include "hi_timestamp.h"

#define MAX_TIMESTAMP_LEN  200

void board_config(void)
{
#if 1
    extern AARCHPTR g_sys_mem_addr_end;
    //g_sys_mem_addr_end = SYS_MEM_BASE + SYS_MEM_SIZE_DEFAULT + 0x100000;
#ifdef YD_PROTOCOL
	g_sys_mem_addr_end = SYS_MEM_BASE + SYS_MEM_SIZE_DEFAULT + 0x7E0000;
#else
	g_sys_mem_addr_end = SYS_MEM_BASE + SYS_MEM_SIZE_DEFAULT + 0x1E0000;
#endif

#ifdef LOSCFG_DRIVERS_USB
    extern unsigned long g_usb_mem_addr_start;
    extern unsigned long g_usb_mem_size;
    g_usb_mem_addr_start = g_sys_mem_addr_end;
    g_usb_mem_size = 0x20000; //src:0x100000(1M), recommend 1M nonCache for usb
#endif

#if defined(LOSCFG_DRIVERS_HIGMAC) || defined(LOSCFG_DRIVERS_HIETH_SF)
    //different board should set right mode:"rgmii" "rmii" "mii"
    //if you don't set :
#if defined(LOSCFG_PLATFORM_HI3559AV100) || defined(LOSCFG_PLATFORM_HI3519AV100)
    hisi_eth_set_phy_mode("rgmii");
#endif
#if defined(LOSCFG_PLATFORM_HI3559AV100)
    //use eth1 higmac,the phy addr is 3
    hisi_eth_set_phy_addr(3);//0~31
#endif
    //different board should set right addr:0~31
    //if you don't set ,driver will detect it automatically
    //hisi_eth_set_phy_addr(0);//0~31
#endif
#endif
}

static void ram_fs_init(void)
{
    int ret = 0;
    ret = mount(NULL, "/ramfs", "ramfs", 0, NULL);
    if (ret) {
        LOGE("mount ramfs failed %d\n", ret);
        return ;
    }
    LOGD("Mount ramfs finished\n");
}

static void mtd_partition_init(void)
{
#ifdef LOSCFG_DRIVERS_MTD_SPI_NOR
    LOGD("spi nor flash init ...\n");
    extern int spinor_init(void);

    if (!spinor_init())
    {
        extern int add_mtd_partition( char * type, UINT32 start_addr, UINT32 length, UINT32 partition_num);
        extern int mount(const char * source, const char * target,
                         const char * filesystemtype, unsigned long mountflags,
                         const void * data);        
        add_mtd_partition("spinor", FLASH_RES_OFFSET, FLASH_RES_SIZE, 0);
        mount("/dev/spinorblk0", FLASH_RES_DIR, "jffs", 0, NULL);
        
        add_mtd_partition("spinor", FLASH_CONFIG_OFFSET, FLASH_CONFIG_SIZE, 1);
        mount("/dev/spinorblk1", FLASH_CONFIG_DIR, "jffs", 0, NULL);
    }
#endif
}

static void net_init(void)
{
    struct netif *pnetif;
    
    tcpip_init(NULL, NULL);
#ifdef LOSCFG_DRIVERS_HIGMAC
    extern struct los_eth_driver higmac_drv_sc;
    pnetif = &(higmac_drv_sc.ac_if);
    higmac_init();
#endif

#ifdef LOSCFG_DRIVERS_HIETH_SF
    extern struct los_eth_driver hisi_eth_drv_sc;
    pnetif = &(hisi_eth_drv_sc.ac_if);
    hisi_eth_init();
#endif

    LOGD("cmd_startnetwork : DHCP_BOUND finished\n");

    netifapi_netif_set_up(pnetif);
}

static void misc_driver_init(void)
{
#ifdef LOSCFG_DRIVERS_UART
    LOGD("uart init ...\n");
    if (uart_dev_init() != 0)
    {
        LOGE("uart_dev_init failed\n");
    }
    if (virtual_serial_init(TTY_DEVICE) != 0)
    {
        LOGE("virtual_serial_init failed\n");
    }
    if (system_console_init(SERIAL) != 0)
    {
        LOGE("system_console_init failed\n");
    }
#endif

#ifdef LOSCFG_DRIVERS_RANDOM
    LOGD("random dev init ...\n");
    extern int ran_dev_register(void);
    ran_dev_register();
#endif

#ifdef LOSCFG_DRIVERS_MMC
//    LOGD("MMC dev init ...\n");
//    extern int SD_MMC_Host_init(void);
//    SD_MMC_Host_init();
#endif

#ifdef LOSCFG_DRIVERS_MEM
    LOGD("mem dev init ...\n");
    extern int mem_dev_register(void);
    mem_dev_register();
#endif

#ifdef LOSCFG_FS_PROC
    LOGD("porc fs init ...\n");
    extern void proc_fs_init(void);
    proc_fs_init();
#endif

#ifdef LOSCFG_DRIVERS_GPIO
    LOGD("gpio init ...\n");
    extern int gpio_dev_init(void);
    gpio_dev_init();
#endif

#ifdef LOSCFG_DRIVERS_NETDEV
#if 0
    LOGD("net init ...\n");
    net_init();
    LOGD("\n************************************************************\n");
#endif
#endif

#ifdef LOSCFG_DRIVERS_USB
    LOGD("usb init ...\n");
//    usb_init(HOST, 0);
#endif

    mtd_partition_init();
    ram_fs_init();
}

void *tskProductInit(void*args)
{
    SET_THREAD_NAME("tskProductInit");
    pthread_detach(pthread_self());

    int ret = 0;
    
    ret = ProductInit();
    AV_RETURN_WITH_INFO_IF_EXPR_FALSE(ret == 0, NULL, "ProductInit");

    ret = ConfigInit();
    AV_RETURN_WITH_INFO_IF_EXPR_FALSE(ret == 0, NULL, "ConfigInit");
    
#ifdef LOG_PUSH_ENABLE	
    ret = LogInit();
    AV_RETURN_WITH_INFO_IF_EXPR_FALSE(ret == 0, NULL, "LogInit");
#endif /* LOG_PUSH_ENABLE */ 
   
	ret = DevInit();
    AV_RETURN_WITH_INFO_IF_EXPR_FALSE(ret == 0, NULL, "DevInit");

#ifndef WIFI_TEST_MODE
    ret = ProtocolInit();
    AV_RETURN_WITH_INFO_IF_EXPR_FALSE(ret == 0, NULL, "ProtocolInit");

    ret = VideoInit();
    AV_RETURN_WITH_INFO_IF_EXPR_FALSE(ret == 0, NULL, "VideoInit");


    ret = AudioInit();
    AV_RETURN_WITH_INFO_IF_EXPR_FALSE(ret == 0, NULL, "AudioInit");

    ret = PowerInit();
    AV_RETURN_WITH_INFO_IF_EXPR_FALSE(ret == 0, NULL, "PowerInit");

    /* set dev params from cfg */
    DevSetParamsFromCfg();
    
#endif /* WIFI_TEST_MODE */

    /* log level set */
    int loglevel = 0;
    DevConfigGetLogLevel(&loglevel);
    HI_LOG_Config(1, 1, loglevel);

#ifndef SYSTEM_SAFE_MODE
    /* register shell cmd */
    product_cmd_register();
#endif /* SYSTEM_SAFE_MODE */

#ifdef DAEMON_ON
    daemon_run();
#endif /* DAEMON_ON */

    extern void CatLogShell(void);
    CatLogShell();

#if defined(TELNET_ON) && !defined(SYSTEM_SAFE_MODE)
    SystemTelnetOn();
#endif /* TELNET_ON */
    
    pthread_exit(0);
    
    return NULL; 
}

static HI_VOID CopyUbootStampToApp(HI_VOID)
{
#ifdef HI3518EV300
    #define UBOOT_STAMP_VALUE_ADDR     0x04019100
    #define UBOOT_STAMP_CNT_ADDR       0x1202016C
    #define UBOOT_STAMP_MAX_CNT        200U
#else
    #define UBOOT_STAMP_CNT_ADDR       0x87D00000
    #define UBOOT_STAMP_VALUE_ADDR     0x87D00010
    #define UBOOT_STAMP_MAX_CNT        200U
#endif

    HI_U32 cnt = readl(UBOOT_STAMP_CNT_ADDR);
    if (cnt > UBOOT_STAMP_MAX_CNT) {
        MLOGE("uboot timestamp num:%d too large than max:%d\n", cnt, UBOOT_STAMP_MAX_CNT);
        return ;
    }

    HI_TIMESTAMP_Item *addr = (HI_TIMESTAMP_Item*)(HI_UINTPTR_T)UBOOT_STAMP_VALUE_ADDR;
    HI_U32 i;

    for (i = 0; i < cnt; i++) {
        HI_TIMESTAMP_MarkEx(addr + i);
    }

    return;
}

void app_init(void)
{
    int ret = 0;
    pthread_t productInitPid;

    LOGI("Date:%s.\n", __DATE__);
    LOGI("Time:%s.\n", __TIME__);
    
#ifdef __HuaweiLite__
    misc_driver_init();

#ifdef HISYSLINK_ENABLE
    int retryCnt = 0;
retry_init:
    ret = HI_HAL_SYSLINK_Init();
    if (ret != 0) {
        if (++retryCnt >= 1) {
            MLOGW("reboot system!\n");
            wifisoc_set_reset_ex("hisyslink init failed");
            sleep(5);
//            SystemReboot("HI_HAL_SYSLINK_Init failed\n");
        } else {
            usleep(300 * 1000);
            goto retry_init;
        }
    }
#endif /* HISYSLINK_ENABLE */

    LOGI("g_sys_mem_addr_end=0x%p,\n",g_sys_mem_addr_end);

    /*init cpp running context on liteos */
    extern char __init_array_start__, __init_array_end__;
    LOS_CppSystemInit((unsigned long)&__init_array_start__, (unsigned long)&__init_array_end__, NO_SCATTER);

    extern HI_VOID SDK_init(void);
    SDK_init();

#ifdef AUDIO_AEC_MODE
    AUDIO_RegisterVQEModule();
#endif /* AUDIO_AEC_MODE */

#endif /* __HuaweiLite__ */

    /*
     * 特别说明: 
     * app_init主函数不能阻塞,否则会导致系统异常,因此除了系统相关初始化,其他功能初始化都放在线程处理
     */
    ret = pthread_create(&productInitPid, NULL, &tskProductInit, NULL);
    AV_NORETURN_WITH_INFO_IF_EXPR_FALSE(ret == 0, "pthread_create tskProductInit");

}

